/*
 * Copyright (C) 2005 - 2013 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008 - 2013 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2006 - 2013 ScriptDev2 <http://www.scriptdev2.com/>
 *
 * Copyright (C) 2010 - 2013 ProjectSkyfire <http://www.projectskyfire.org/>
 *
 * Copyright (C) 2011 - 2013 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/* ScriptData
 SDName: Boss_Nightbane
 SD%Complete: 80
 SDComment: SDComment: Timers may incorrect
 SDCategory: Karazhan
 EndScriptData */

#include "ScriptPCH.h"
#include "karazhan.h"

//phase 1
#define SPELL_BELLOWING_ROAR        39427
#define SPELL_CHARRED_EARTH         30129
#define SPELL_DISTRACTING_ASH       30130
#define SPELL_SMOLDERING_BREATH     30210
#define SPELL_TAIL_SWEEP            25653
//phase 2
#define SPELL_RAIN_OF_BONES         37098
#define SPELL_SMOKING_BLAST         37057
#define SPELL_FIREBALL_BARRAGE      30282
#define SPELL_SEARING_CINDERS       30127
#define SPELL_SUMMON_SKELETON       30170

#define EMOTE_SUMMON                "An ancient being awakens in the distance..."
#define YELL_AGGRO                  "What fools! I shall bring a quick end to your suffering!"
#define YELL_FLY_PHASE              "Miserable vermin. I shall exterminate you from the air!"
#define YELL_LAND_PHASE_1           "Enough! I shall land and crush you myself!"
#define YELL_LAND_PHASE_2           "Insects! Let me show you my strength up close!"
#define EMOTE_BREATH                "takes a deep breath."

float IntroWay[8][3] = { { -11053.37f, -1794.48f, 149.00f }, { -11141.07f,
        -1841.40f, 125.00f }, { -11187.28f, -1890.23f, 125.00f }, { -11189.20f,
        -1931.25f, 125.00f }, { -11153.76f, -1948.93f, 125.00f }, { -11128.73f,
        -1929.75f, 125.00f }, { -11140.00f, -1915.00f, 122.00f }, { -11163.00f,
        -1903.00f, 91.473f } };

class boss_nightbane: public CreatureScript {
public:
    boss_nightbane() :
            CreatureScript("boss_nightbane") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new boss_nightbaneAI(pCreature);
    }

    struct boss_nightbaneAI: public ScriptedAI {
        boss_nightbaneAI(Creature* c) :
                ScriptedAI(c) {
            pInstance = c->GetInstanceScript();
            Intro = true;
        }

        InstanceScript* pInstance;

        uint32 Phase;

        bool RainBones;
        bool Skeletons;

        uint32 BellowingRoarTimer;
        uint32 CharredEarthTimer;
        uint32 DistractingAshTimer;
        uint32 SmolderingBreathTimer;
        uint32 TailSweepTimer;
        uint32 RainofBonesTimer;
        uint32 SmokingBlastTimer;
        uint32 FireballBarrageTimer;
        uint32 SearingCindersTimer;

        uint32 FlyCount;
        uint32 FlyTimer;

        bool Intro;
        bool Flying;
        bool Movement;

        uint32 WaitTimer;
        uint32 MovePhase;

        void Reset() {
            BellowingRoarTimer = 30000;
            CharredEarthTimer = 15000;
            DistractingAshTimer = 20000;
            SmolderingBreathTimer = 10000;
            TailSweepTimer = 12000;
            RainofBonesTimer = 10000;
            SmokingBlastTimer = 20000;
            FireballBarrageTimer = 13000;
            SearingCindersTimer = 14000;
            WaitTimer = 1000;

            Phase = 1;
            FlyCount = 0;
            MovePhase = 0;

            me->SetSpeed(MOVE_RUN, 2.0f);
            me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
            me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
            me->setActive(true);

            if (pInstance) {
                if (pInstance->GetData(TYPE_NIGHTBANE) == DONE
                        || pInstance->GetData(TYPE_NIGHTBANE) == IN_PROGRESS)
                    me->DisappearAndDie();
                else
                    pInstance->SetData(TYPE_NIGHTBANE, NOT_STARTED);
            }

            HandleTerraceDoors(true);

            Flying = false;
            Movement = false;

            if (!Intro) {
                me->SetHomePosition(IntroWay[7][0], IntroWay[7][1],
                        IntroWay[7][2], 0);
                me->GetMotionMaster()->MoveTargetedHome();
            }
        }

        void HandleTerraceDoors(bool open) {
            if (pInstance) {
                pInstance->HandleGameObject(
                        pInstance->GetData64(DATA_MASTERS_TERRACE_DOOR_1),
                        open);
                pInstance->HandleGameObject(
                        pInstance->GetData64(DATA_MASTERS_TERRACE_DOOR_2),
                        open);
            }
        }

        void EnterCombat(Unit * /*who*/) {
            if (pInstance)
                pInstance->SetData(TYPE_NIGHTBANE, IN_PROGRESS);

            HandleTerraceDoors(false);
            me->MonsterYell(YELL_AGGRO, LANG_UNIVERSAL, NULL);
        }

        void AttackStart(Unit* who) {
            if (!Intro && !Flying)
                ScriptedAI::AttackStart(who);
        }

        void JustDied(Unit* /*killer*/) {
            if (pInstance)
                pInstance->SetData(TYPE_NIGHTBANE, DONE);

            HandleTerraceDoors(true);
        }

        void MoveInLineOfSight(Unit *who) {
            if (!Intro && !Flying)
                ScriptedAI::MoveInLineOfSight(who);
        }

        void MovementInform(uint32 type, uint32 id) {
            if (type != POINT_MOTION_TYPE)
                return;

            if (Intro) {
                if (id >= 8) {
                    Intro = false;
                    me->SetHomePosition(IntroWay[7][0], IntroWay[7][1],
                            IntroWay[7][2], 0);
                    return;
                }

                WaitTimer = 1;
            }

            if (Flying) {
                if (id == 0) {
                    me->MonsterTextEmote(EMOTE_BREATH, 0, true);
                    Flying = false;
                    Phase = 2;
                    return;
                }

                if (id == 3) {
                    MovePhase = 4;
                    WaitTimer = 1;
                    return;
                }

                if (id == 8) {
                    Flying = false;
                    Phase = 1;
                    Movement = true;
                    return;
                }

                WaitTimer = 1;
            }
        }

        void JustSummoned(Creature *summoned) {
            summoned->AI()->AttackStart(me->getVictim());
        }

        void TakeOff() {
            me->MonsterYell(YELL_FLY_PHASE, LANG_UNIVERSAL, NULL);

            me->InterruptSpell(CURRENT_GENERIC_SPELL);
            me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
            me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
            (*me).GetMotionMaster()->Clear(false);
            (*me).GetMotionMaster()->MovePoint(0, IntroWay[2][0],
                    IntroWay[2][1], IntroWay[2][2]);

            Flying = true;

            FlyTimer = urand(45000, 60000); //timer wrong between 45 and 60 seconds
            ++FlyCount;

            RainofBonesTimer = 5000; //timer wrong (maybe)
            RainBones = false;
            Skeletons = false;
        }

        void UpdateAI(const uint32 diff) {
            /* The timer for this was never setup apparently, not sure if the code works properly:
             if (WaitTimer <= diff)
             {
             if (Intro)
             {
             if (MovePhase >= 7)
             {
             me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
             me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
             me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]);
             }
             else
             {
             me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]);
             ++MovePhase;
             }
             }
             if (Flying)
             {
             if (MovePhase >= 7)
             {
             me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
             me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
             me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]);
             }
             else
             {
             me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]);
             ++MovePhase;
             }
             }

             WaitTimer = 0;
             } else WaitTimer -= diff;
             */

            if (!UpdateVictim())
                return;

            if (Flying)
                return;

            //  Phase 1 "GROUND FIGHT"
            if (Phase == 1) {
                if (Movement) {
                    DoStartMovement(me->getVictim());
                    Movement = false;
                }

                if (BellowingRoarTimer <= diff) {
                    DoCast(me->getVictim(), SPELL_BELLOWING_ROAR);
                    BellowingRoarTimer = urand(30000, 40000);
                } else
                    BellowingRoarTimer -= diff;

                if (SmolderingBreathTimer <= diff) {
                    DoCast(me->getVictim(), SPELL_SMOLDERING_BREATH);
                    SmolderingBreathTimer = 20000;
                } else
                    SmolderingBreathTimer -= diff;

                if (CharredEarthTimer <= diff) {
                    if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        DoCast(pTarget, SPELL_CHARRED_EARTH);
                    CharredEarthTimer = 20000;
                } else
                    CharredEarthTimer -= diff;

                if (TailSweepTimer <= diff) {
                    if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        if (!me->HasInArc(M_PI, pTarget))
                            DoCast(pTarget, SPELL_TAIL_SWEEP);
                    TailSweepTimer = 15000;
                } else
                    TailSweepTimer -= diff;

                if (SearingCindersTimer <= diff) {
                    if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        DoCast(pTarget, SPELL_SEARING_CINDERS);
                    SearingCindersTimer = 10000;
                } else
                    SearingCindersTimer -= diff;

                uint32 Prozent = uint32(me->GetHealthPct());

                if (Prozent < 75 && FlyCount == 0) // first take off 75%
                    TakeOff();

                if (Prozent < 50 && FlyCount == 1) // secound take off 50%
                    TakeOff();

                if (Prozent < 25 && FlyCount == 2) // third take off 25%
                    TakeOff();

                DoMeleeAttackIfReady();
            }

            //Phase 2 "FLYING FIGHT"
            if (Phase == 2) {
                if (!RainBones) {
                    if (!Skeletons) {
                        for (uint8 i = 0; i <= 3; ++i) {
                            DoCast(me->getVictim(), SPELL_SUMMON_SKELETON);
                            Skeletons = true;
                        }
                    }

                    if (RainofBonesTimer < diff && !RainBones) // only once at the beginning of phase 2
                            {
                        DoCast(me->getVictim(), SPELL_RAIN_OF_BONES);
                        RainBones = true;
                        SmokingBlastTimer = 20000;
                    } else
                        RainofBonesTimer -= diff;

                    if (DistractingAshTimer <= diff) {
                        if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                            DoCast(pTarget, SPELL_DISTRACTING_ASH);
                        DistractingAshTimer = 2000; //timer wrong
                    } else
                        DistractingAshTimer -= diff;
                }

                if (RainBones) {
                    if (SmokingBlastTimer <= diff) {
                        DoCast(me->getVictim(), SPELL_SMOKING_BLAST);
                        SmokingBlastTimer = 1500; //timer wrong
                    } else
                        SmokingBlastTimer -= diff;
                }

                if (FireballBarrageTimer <= diff) {
                    if (Unit *pTarget = SelectUnit(SELECT_TARGET_FARTHEST, 0))
                        DoCast(pTarget, SPELL_FIREBALL_BARRAGE);
                    FireballBarrageTimer = 20000;
                } else
                    FireballBarrageTimer -= diff;

                if (FlyTimer <= diff) //landing
                        {
                    me->MonsterYell(
                            RAND(*YELL_LAND_PHASE_1, *YELL_LAND_PHASE_2),
                            LANG_UNIVERSAL, NULL);

                    me->GetMotionMaster()->Clear(false);
                    me->GetMotionMaster()->MovePoint(3, IntroWay[3][0],
                            IntroWay[3][1], IntroWay[3][2]);

                    Flying = true;
                } else
                    FlyTimer -= diff;
            }
        }
    };
};

void AddSC_boss_nightbane() {
    new boss_nightbane();
}
